(** Standard collection of widgets based on Fr. *)

open Fr


(** {2 Data types} *)

type widget

type orientation = [ `Horizontal | `Vertical ]
type justification = [ `Left | `Center | `Right | `Full ]
type direction = [ `North | `South | `East | `West ]

type image

type button = [ `Left | `Middle | `Right | `Button of int ]
type modifier = [ `Shift | `Control | `Meta | `Caps | `Mod of int ]
type key = [
	| `Char of char
	| `Numpad of char
	| `Function of int
	| `Escape | `Backspace | `Tab | `Enter | `Key of int ]
type 'a input = <
	pointer: ('a * 'a) option behavior;
	buttons: button list behavior;
	click: button event;
	scroll: direction event;
	modifiers: modifier list behavior;
	keypress: key event;
	size: ('a * 'a) behavior;
>

(** {2 Static widgets} *)

(** [empty] is a widget which simply takes up space.  It is similar to
    an hfill in TeX. *)
val empty: widget

(** [label text] creates a label which displays [text]. *)
val label:
	?justification: justification ->
	?selectable: bool ->
	string -> widget
(** @param justification 
      justification of [text]; defaults to `LEFT
      (note that this only really affects multi-line labels, since the
      widget itself shrink-wraps around the text and must be aligned
      by means of empty widgets)
    @param selectable
      whether the user should be able to select text in the label;
      defaults to false *)

(** [image_label image] creates a label which displays [image]. *)
val image_label:
	image -> widget


(** {2 Event generating widgets} *)

(** [button value] creates a button which, when clicked, emits an event with
    the value [value]. *)
val button:
	?enabled: bool behavior ->
	?label: string ->
	?icon: image ->
	'a -> widget * 'a event
(** @param label  optional static label
    @param icon  optional static icon *)

val button_group:
	?enabled: bool behavior ->
	(string * 'a) list -> widget list * 'a event

(** {2 Behavior generating widgets} *)

(** [checkbox i] creates a checkbox which allows the user to select a
    boolean value.  The initial value is [i]. *)
val checkbox:
	?enabled: bool behavior ->
	?label: string ->
	bool -> widget * bool behavior
(** @param label  optional static label *)

val tristate_checkbox:
	?enabled: bool behavior ->
	?label: string ->
	bool option -> widget * bool option behavior

(** [toggle_button i] creates a button which allows the user to select a
    boolean value.  The initial value is [i]. *)
val toggle_button:
	?enabled: bool behavior ->
	?label: string ->
	bool -> widget * bool behavior
(** @param label  optional static label *)

val tristate_toggle_button:
	?enabled: bool behavior ->
	?label: string ->
	bool option -> widget * bool option behavior

(** [radio_button_group options i] creates a group of radio buttons which
    allow the user to choose one value from a set.  The set of values is
    given by the non-empty list of tuples [options] which associates a
    descriptive string with each value.  The initial selection is [i].  If
    [i] is not in the list then the first value in the list will be used
    instead. *)
val radio_button_group:
	?enabled: bool behavior ->
	(string * 'a) list -> 'a -> widget list * 'a behavior

(** [tristate_radio_button_group] is the same as [radio_button_group] but
    allows the user to choose none of the options.  Also unlike
    [radio_button_group], [options] may be an empty list. *)
val tristate_radio_button_group:
	?enabled: bool behavior ->
	(string * 'a) list -> 'a option -> widget list * 'a option behavior

(** [slider orientation i] creates a slider which allows the user to select
    a floating point value within a certain range.  The initial value is
    [i]. *)
val slider: orientation ->
	?enabled: bool behavior ->
	?range: float * float ->
	?step: float ->
	float -> widget * float behavior
(** @param range
      A tuple behavior specifying the minimum and maximum values the user is
      allowed to select.  Defaults to [(0., i *. 2.)].
    @param step 
      The step by which the keyboard adjusts the value.  Defaults to
      [(snd range -. fst range) /. 10.].
    
    TODO: should range be required and init optional? *)

(** alias for [slider `Horizontal] *)
val hslider:
	?enabled: bool behavior ->
	?range: float * float ->
	?step: float ->
	float -> widget * float behavior

(** alias for [slider `Vertical] *)
val vslider:
	?enabled: bool behavior ->
	?range: float * float ->
	?step: float ->
	float -> widget * float behavior
	
(** [text_entry i] creates text box which allows the user to enter a
    string.  The initial value is [i]. *)
val text_entry:
	?enabled: bool behavior ->
	?visible: bool behavior ->
	?width: int ->
	string -> widget * string behavior
(** @param visible
      When false, text entered by user is not visible on the screen (e.g. for
      password entry).  Defaults to true.
    @param width  width of text box in characters *)

val spin_box:
	?enabled: bool behavior ->
	?range: float * float ->
	?step: float ->
	float -> widget * float behavior

val list_box:
	?enabled: bool behavior ->
	('a -> string) -> 'a list behavior -> 'a list -> widget * 'a list behavior

val combo_box:
	?enabled: bool behavior ->
	?columns: int ->
	('a -> string) -> 'a list -> 'a -> widget * 'a behavior

val combo_box_entry:
	?enabled: bool behavior ->
	?columns: int ->
	?autocomplete: bool ->
	string list -> string -> widget * string behavior

(** {2 Event watching widgets} *)

(** [progress_ticker event] creates a progress indicator which steps through
    an animation on each occurrence of [event]. *)
val progress_ticker:
	?text: string behavior ->
	unit event -> widget
(** @param text  optional label *)

(** [log_area event] creates a widget which collects the messages in [event] in a
    log-like fashion. *)
val log_area:
	string event -> widget

(** {2 Behavior watching widgets} *)

(** [text_view text] creates text box which displays the value of the
    behavior [text].  This is like a [dynamic_label] but allows the user to
    perform the same operations as a [text_entry] (such as copying). *)
val text_view:
	?width: int ->
	string behavior -> widget
(** @param width  width of text box in characters *)

(** [text_area_view text] creates text area which displays the value of the
    behavior [text].  This is like a [text_view] but has the ability
    to display multiple lines of text. *)
val text_area_view:
	?monospaced: bool ->
	string behavior -> widget
(** @param monospaced  display text using a fixed-width font; default false *)

(** [progress_bar fraction] creates a progress bar which displays the value
    of [fraction].  A [fraction] of [0.] indicates no progress while [1.]
    indicates completion.  If [fraction] is outside this range it is clamped
    to be within it. *)
val progress_bar:
	?text: string behavior ->
	float behavior -> widget
(** @param text  optional label *)


(** {2 Dialog boxes} *)

(** [alert message] displays a message box with the string [message] and
    waits for the user's acknowledgement. *)
val alert:
	?parent: widget ->
	?title: string ->
	?icon: image ->
	?okay: string ->
	?buttons: widget list ->
	string -> unit
(** @param parent  option widget with which to associate message box
    @param title  optional title
    @param okay  text for "Okay" button, defaults to "Okay"
    @param buttons  additional buttons to be displayed alongside options *)

(** [message_box child options null] displays a message box containing
    the widget [child], and waits for the user to make a selection from
    [options] before returning the selection's value.  [options] is a list
    of [(label, value)] pairs describing the possible choices.  If the user
    chooses not to make a selection (e.g. closes the message box) then
    [null] is returned instead. *)
(*val message_box:
	?parent: widget ->
	?title: string ->
	?default: 'a ->
	?buttons: widget list ->
	widget -> (string * 'a) list -> 'a -> 'a*)
(** @param parent  option widget with which to associate message box
    @param title  optional title
    @param default  initially selected choice
    @param buttons  additional buttons to be displayed alongside options *)


(** {2 Menus and toolbars} *)

type action
type action_group

val action:
	?enabled: bool behavior ->
	?icon: image ->
	?label: string ->
	?tooltip: string ->
	string -> 'a -> action * 'a event

val toggle_action:
	?enabled: bool behavior ->
	?icon: image ->
	?label: string ->
	?tooltip: string ->
	string -> bool -> action * bool behavior

val text_radio_action_group:
	?enabled: bool behavior ->
	(string * 'a) list -> 'a -> action list * 'a behavior

val submenu:
	?enabled: bool behavior ->
	?icon: image ->
	?label: string ->
	?tooltip: string ->
	string -> action_group -> action

val group:
	action list -> action_group

val join_groups:
	action_group list -> action_group

val switch_a:
	action_group -> action_group event -> action_group

val collapse_a:
	action_group behavior -> action_group

val toolbar:
	orientation ->
	?text: bool ->
	?large: bool ->
	action_group -> widget

val htoolbar:
	?text: bool ->
	?large: bool ->
	action_group -> widget

val vtoolbar:
	?text: bool ->
	?large: bool ->
	action_group -> widget

(** {2 Containers} *)

(** [frame widget] wraps a widget in a decorative frame. *)
val frame:
	?label: string ->
	widget -> widget
(** @param label  optional label to appear on frame *)

(** [scroll_box widget] adds scrollbars to a widget. *)
val scroll_box:
	widget -> widget

(** [box orientation widgets] creates a widget composed of physical widgets
    [widgets] juxtaposed in a box. *)
val box: orientation ->
	?separated: bool ->
	widget list -> widget
(** @param separated  separate widgets with lines *)

(** alias for [box `Horizontal] *)
val hbox:
	?separated: bool ->
	widget list -> widget

(** alias for [box `Vertical] *)
val vbox:
	?separated: bool ->
	widget list -> widget

val flow: orientation ->
	?justification: justification ->
	widget list -> widget

val hflow:
	?justification: justification ->
	widget list -> widget

val vflow:
	?justification: justification ->
	widget list -> widget

val split: orientation ->
	?position: float ->
	widget * widget -> widget

val hsplit:
	?position: float ->
	widget * widget -> widget

val vsplit:
	?position: float ->
	widget * widget -> widget

val tabbed:
	?position: direction ->
	?init: widget ->
	(string * widget) list -> widget

(** {3 Constraints} *)

type 'a size_constraint
type width_constraint = [ `Horizontal ] size_constraint
type height_constraint = [ `Vertical ] size_constraint
val size_constraint: ([< orientation ] as 'a) -> 'a size_constraint
val width_constraint: unit -> width_constraint
val height_constraint: unit -> height_constraint

val sized_box:
	([< orientation ] as 'a) ->
	?separated: bool ->
	(widget * 'a size_constraint) list -> widget

val sized_hbox:
	?separated: bool ->
	(widget * width_constraint) list -> widget

val sized_vbox:
	?separated: bool ->
	(widget * height_constraint) list -> widget

(** {3 Meta-containers} *)

val switch_w:
	widget -> widget event -> widget

val collapse_w:
	widget behavior -> widget

val switch_we:
	(widget * 'a event) -> (widget * 'a event) event -> widget * 'a event

val collapse_we:
	(widget * 'a event) behavior -> widget * 'a event

val switch_wb:
	(widget * 'a behavior) -> (widget * 'a behavior) event -> widget * 'a behavior

val collapse_wb:
	(widget * 'a behavior) behavior -> widget * 'a behavior

val sswitch_wb:
	('a -> widget * 'a behavior) -> 'a -> ('a -> widget * 'a behavior) event -> widget * 'a behavior

val scollapse_wb:
	'a -> ('a -> widget * 'a behavior) behavior -> widget * 'a behavior


(** {3 Windows} *)

(** Type of a physical window *)
type window

(** [window widget] creates a toplevel window containing physical widget
    [widget].  Also returns an event triggered by the window's implicit
    "close" button (which does not actually close the window). *)
val window:
	?visible: bool behavior ->
	?label: string ->
	?menu_bar: action_group ->
	?status_bar: widget ->
	widget -> window * unit event
(** @param label  optional title
    @param menu_bar  optional menu bar to be displayed in window
    @param status_bar  optional status bar to be displayed in window *)

val swindow:
	?visible: bool behavior ->
	?label: string ->
	?menu_bar: action_group ->
	?status_bar: widget ->
	('a -> widget * 'a behavior) -> 'a -> window * (unit event * 'a behavior)

val show: window list behavior -> unit


(** {2 Main event loop} *)

(** [run e] runs the main event loop of the GUI system until event [e]
    occurs.  The value of the occurrence of [e] is returned. *)
val run: 'a event -> 'a

(** [run_window (window, e)] is a convenience function which displays
    [window] on the screen, and waits for event [e] to occur, at which time
    the window is closed.  Returns the value of the occurrence of [e]. *)
val run_window: (window * 'a event) -> 'a


(** {2 Time functions} *)

(** [every s] creates an event which occurs once approximately every [s]
    seconds.  The value of the event is the actual amount of time, in
    seconds, which passed since the last event. *)
val every: float -> float event

(** [timer s] creates a behavior which changes approximately every [s]
    seconds.  Its value is the amount of time which has passed since the
    behavior was created.  Identical to [collect_b (+.) 0. (every s)]. *)
val timer: float -> float behavior


(** {2 Images} *)

val load_image: string -> image
val load_image_lazy: string -> image

(** Built-in stock images. *)
module Images: sig
	val info: image
	val warning: image
	val error: image
	val question: image

	val bold: image
	val italic: image
	val strikethrough: image
	val underline: image

	val indent: image
	val unindent: image
	val justify_center: image
	val justify_full: image
	val justify_left: image
	val justify_right: image

	val select_color: image
	val select_font: image
	val spell_check: image

	val okay: image
	val apply: image
	val cancel: image
	val yes: image
	val no: image

	val cdrom: image
	val floppy: image
	val hard_drive: image
	val network_drive: image

	val add: image
	val remove: image

	val clear: image
	val delete: image
	val undelete: image

	val copy: image
	val cut: image
	val paste: image

	val find: image
	val find_and_replace: image

	val sort_ascending: image
	val sort_descending: image

	val goto_first: image
	val goto_last: image
	val goto_top: image
	val goto_bottom: image
	val go_down: image
	val go_up: image

	val go_back: image
	val go_forward: image
	val home: image
	val refresh: image
	val stop: image

	val close: image
	val help: image

	val missing_image: image

	val new_file: image
	val open_file: image
	val save: image
	val save_as: image
	val print: image
	val print_preview: image
	val undo: image
	val redo: image

	val zoom_100: image
	val zoom_fit: image
	val zoom_in: image
	val zoom_out: image
end


(** {2 Useful functions} *)

val fix_we: ('c -> 'a event) -> ('a event -> 'b * 'c) -> 'b * 'c
val fix_wb: ('c -> 'a behavior) -> ('a behavior -> 'b * 'c) -> 'b * 'c


(**/**)
val lift_signal: (callback: ('a -> unit) -> _) -> 'a event
val lift_event: bool -> (callback: ('a -> bool) -> _) -> 'a event
val lift_input:
	p2c: (float * float -> 'a * 'a) ->
	d2c: (float * float -> 'a * 'a) ->
	GObj.widget -> GObj.event_ops -> 'a input
class simple_widget: ?enabled: bool behavior -> ?expand: bool -> #GObj.widget -> object
	method widget: GObj.widget
	method expand: bool
end
class behavior_view_widget: ?enabled: bool behavior -> ?expand: bool -> #GObj.widget -> ('a -> unit) -> 'a behavior -> object
	inherit simple_widget
end
val add_popup_menu: ?menu: action_group -> ?popup: unit event -> ?detachable: bool -> #GObj.widget -> unit
val coerce_widget: #simple_widget -> widget
val uncoerce_widget: widget -> simple_widget
val warn: string -> unit
val unregister_with: #GObj.widget -> endpoint -> unit
val register_e_with: #GObj.widget -> 'a event -> unit
val register_b_with: #GObj.widget -> 'a behavior -> unit
